package com.itheima.es.service.impl;

import com.alibaba.fastjson.JSON;
import com.itheima.es.entity.HotelEntity;
import com.itheima.es.mapper.HotelMapper;
import com.itheima.es.service.HotelService;
import org.apache.lucene.search.Query;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class HotelServiceImpl implements HotelService {

    @Autowired
    private HotelMapper hotelMapper;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    //批量导入
//    @Override
//    public int addDocToES() {
//        //1.先去mysql查询出来
//        List<HotelEntity> list = hotelMapper.selectList(null);
//        //使用restHighLevelClient 对象 发请求 把数据插入到es的hotel索引表中
//        for (HotelEntity hotelEntity : list) {
//            IndexRequest indexRequest=new IndexRequest("hotel").id(hotelEntity.getId()+"");
//            String s = JSON.toJSONStringWithDateFormat(hotelEntity,"yyyy-MM-dd");
//            indexRequest.source(s, XContentType.JSON);
//            try {
//                //说白就是发了请求而已 网络连接!!!
//                IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
//                System.out.println(response.status());
//            } catch (IOException e) {
//                throw new RuntimeException(e);
//            }
//        }
//        return list.size();
//    }
    @Override
    public int addDocToES() {
        //1.先去mysql查询出来 要不要改造成分页!!!
        List<HotelEntity> list = hotelMapper.selectList(null);
        //使用restHighLevelClient 对象 发请求 把数据插入到es的hotel索引表中
        //es 提供 bulk的api
        //代表一个请求的集合
        BulkRequest bulkRequest=new BulkRequest();

        //循环数据
        for (HotelEntity hotelEntity : list) {
            IndexRequest indexRequest=new IndexRequest("hotel").id(hotelEntity.getId()+"");
            String s = JSON.toJSONStringWithDateFormat(hotelEntity,"yyyy-MM-dd");
            indexRequest.source(s, XContentType.JSON);
            //将创建好的连接对象 添加bulk对象中
            bulkRequest.add(indexRequest);
        }
        try {
            //一次发出 减少网络连接的消耗
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            System.out.println(bulkResponse.status());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list.size();
    }

    //查询全部
    @Override
    public Map<String, Object> matchAllQuery() {
        try {
            //查询所有
            //第一步构建查询的java api代码
            SearchRequest searchRequest=new SearchRequest("hotel");
            SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();

            QueryBuilder matchAllQueryBuilder= QueryBuilders.matchAllQuery();
            searchSourceBuilder.query(matchAllQueryBuilder);

            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            //第二步构建 结果解析
            SearchHits searchResponseHits = searchResponse.getHits();
            //获取到了命中 总条数
            long total = searchResponseHits.getTotalHits().value;
            SearchHit[] searchHits = searchResponseHits.getHits();

            List<HotelEntity> list = new ArrayList<>();
            //处理数据!!!
            if (searchHits!=null||searchHits.length>0){
                for (SearchHit searchHit : searchHits) {
                    String sourceAsString = searchHit.getSourceAsString();
                    //得到字符串转换java对象
                    HotelEntity hotelEntity = JSON.parseObject(sourceAsString, HotelEntity.class);
                    list.add(hotelEntity);
                }
            }
            //行至此处
            //得到两个数据一个是总个数
            //一个查询到数据的list集合
            Map<String, Object> map = new HashMap<>();
            map.put("total",total);
            map.put("list",list);
            return map;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    //分页查询
    @Override
    public Map<String, Object> pageQuery(int current, int size) {

        try {
            //查询所有
            //第一步构建查询的java api代码
            SearchRequest searchRequest=new SearchRequest("hotel");
            SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();

            QueryBuilder matchAllQueryBuilder= QueryBuilders.matchAllQuery();
            searchSourceBuilder.query(matchAllQueryBuilder);

            //补充一下 查询请求当中的 from参数和size参数即可

            searchSourceBuilder.from((current-1)*size);
            searchSourceBuilder.size(size);

            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            //第二步构建 结果解析
            SearchHits searchResponseHits = searchResponse.getHits();
            //获取到了命中 总条数
            long total = searchResponseHits.getTotalHits().value;
            SearchHit[] searchHits = searchResponseHits.getHits();

            List<HotelEntity> list = new ArrayList<>();
            //处理数据!!!
            if (searchHits!=null||searchHits.length>0){
                for (SearchHit searchHit : searchHits) {
                    String sourceAsString = searchHit.getSourceAsString();
                    //得到字符串转换java对象
                    HotelEntity hotelEntity = JSON.parseObject(sourceAsString, HotelEntity.class);
                    list.add(hotelEntity);
                }
            }
            //照顾前端的展示
            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", total);
            map.put("current", current);
            //设置总页数
            map.put("totalPage",(total+size-1)/size);
            return map;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //按照品牌精确查询
    @Override
    public Map<String, Object> brandTermQuery(int current, int size, Map<String, Object> searchParam) {

        //todo 按品牌精确查询实现

        return null;
    }

    //根据酒店名称匹配查询
    @Override
    public Map<String, Object> nameMatchQuery(Integer current, Integer size, Map<String, Object> searchParam) {


        /*//设置查询
        SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();


        //todo 根据酒店名称匹配查询实现

        //设置分页
        searchSourceBuilder.from((current - 1) * size);
        searchSourceBuilder.size(size);

        searchRequest.source(searchSourceBuilder);

        //处理查询结果
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            List<HotelEntity> list = new ArrayList<>();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                list.add(JSON.parseObject(sourceAsString, HotelEntity.class));
            }

            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", totalHits);
            map.put("current", current);
            //设置总页数
            map.put("totalPage", (totalHits + size - 1) / size);

            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }

    //根据酒店品牌模糊查询
    @Override
    public Map<String, Object> nameWildcardQuery(Integer current, Integer size, Map<String, Object> searchParam) {

        /*//设置查询
        SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //todo 根据酒店名称模糊查询


        //设置分页
        searchSourceBuilder.from((current - 1) * size);
        searchSourceBuilder.size(size);

        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            List<HotelEntity> list = new ArrayList<>();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                list.add(JSON.parseObject(sourceAsString, HotelEntity.class));
            }

            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", totalHits);
            map.put("current", current);
            //设置总页数
            map.put("totalPage", (totalHits + size - 1) / size);

            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }

    //根据name,synopsis,area,address进行多域查询
    @Override
    public Map<String, Object> searchQueryStringQuery(Integer current, Integer size, Map<String, Object> searchParam) {

        /*//设置查询
        SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //todo 根据name,synopsis,area,address进行多域查询

        //设置分页
        searchSourceBuilder.from((current - 1) * size);
        searchSourceBuilder.size(size);

        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            List<HotelEntity> list = new ArrayList<>();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                list.add(JSON.parseObject(sourceAsString, HotelEntity.class));
            }

            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", totalHits);
            map.put("current", current);
            //设置总页数
            map.put("totalPage", (totalHits + size - 1) / size);

            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }

    //搜索框自动提示
    @Override
    public List<String> searchSuggestInfo(String key) {

        /*//定义结果集
        List<String> result = new ArrayList<>();

        //设置查询
        SearchRequest searchRequest = new SearchRequest("suggest");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //todo 构建自动补全搜索

        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            //todo 处理自动补全查询结果
			
			
			
			//todo 向索引库增量添加查询条件


            return result;
        } catch (IOException e) {
            e.printStackTrace();
        }*/

        return null;
    }

    //根据销量排序查询
    @Override
    public Map<String, Object> salesSortQuery(Integer current, Integer size, Map<String, Object> searchParam) {

       /* //设置查询
        SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //todo 设置按销量排序

        //设置分页
        searchSourceBuilder.from((current - 1) * size);
        searchSourceBuilder.size(size);

        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            List<HotelEntity> list = new ArrayList<>();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                list.add(JSON.parseObject(sourceAsString, HotelEntity.class));
            }

            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", totalHits);
            map.put("current", current);
            //设置总页数
            map.put("totalPage", (totalHits + size - 1) / size);
            map.put("sortWay", searchParam.get("sortWay"));


            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }

    //根据价格范围查询
    @Override
    public Map<String, Object> priceRangeQuery(Integer current, Integer size, Map<String, Object> searchParam) {

        /*//设置查询
        SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //todo 根据价格范围查询


        //设置分页
        searchSourceBuilder.from((current - 1) * size);
        searchSourceBuilder.size(size);

        searchRequest.source(searchSourceBuilder);

        //处理查询结果
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            List<HotelEntity> list = new ArrayList<>();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                list.add(JSON.parseObject(sourceAsString, HotelEntity.class));
            }

            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", totalHits);
            map.put("current", current);
            //设置总页数
            map.put("totalPage", (totalHits + size - 1) / size);

            map.put("minPrice", searchParam.get("minPrice"));
            map.put("maxPrice", searchParam.get("maxPrice"));

            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }

    //多条件查询
    //多域、品牌精确、城市精确、星级精确、价格范围、销量排序
    @Override
    public Map<String, Object> searchBoolQuery(Integer current, Integer size, Map<String, Object> searchParam) {

        /*//设置查询
        SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //设置查询方式
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //todo 多条件查询 ：多域、品牌精确、城市精确、星级精确、价格范围、销量排序

        //设置分页
        searchSourceBuilder.from((current - 1) * size);
        searchSourceBuilder.size(size);

        searchRequest.source(searchSourceBuilder);

        //处理查询结果
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            List<HotelEntity> list = new ArrayList<>();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                list.add(JSON.parseObject(sourceAsString, HotelEntity.class));
            }

            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", totalHits);
            map.put("current", current);
            //设置总页数
            map.put("totalPage", (totalHits + size - 1) / size);

            map.put("brand", searchParam.get("brand"));
            map.put("area", searchParam.get("area"));
            map.put("specs", searchParam.get("specs"));
            map.put("sortWay", searchParam.get("sortWay"));
            map.put("minPrice", searchParam.get("minPrice"));
            map.put("maxPrice", searchParam.get("maxPrice"));

            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }

    //按名称高亮查询
    @Override
    public Map<String, Object> searchHighLight(Integer current, Integer size, Map<String, Object> searchParam) {

        /*//设置查询
        SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //设置查询方式
        if (!ObjectUtils.isEmpty(searchParam.get("condition"))) {
            QueryBuilder queryBuilder = QueryBuilders.termQuery("name",searchParam.get("condition"));
            searchSourceBuilder.query(queryBuilder);
        }
        //设置分页
        searchSourceBuilder.from((current - 1) * size);
        searchSourceBuilder.size(size);

        //todo 查询高亮设置

        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            List<HotelEntity> list = new ArrayList<>();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                HotelEntity hotelEntity = JSON.parseObject(sourceAsString, HotelEntity.class);

                //todo  处理高亮结果

                list.add(hotelEntity);
            }

            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", totalHits);
            map.put("current", current);
            //设置总页数
            map.put("totalPage", (totalHits + size - 1) / size);

            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }




    //地址纠错查询
    @Override
    public Map<String, Object> searchFuzzyQuery(Integer current, Integer size, Map<String, Object> searchParam) {

        /*//设置查询
        SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //设置查询方式
        //todo 设置城市为纠错查询

        searchSourceBuilder.query(queryBuilder);

        //设置分页
        searchSourceBuilder.from((current - 1) * size);
        searchSourceBuilder.size(size);

        searchRequest.source(searchSourceBuilder);

        // 处理查询结果
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            List<HotelEntity> list = new ArrayList<>();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                list.add(JSON.parseObject(sourceAsString, HotelEntity.class));
            }

            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", totalHits);
            map.put("current", current);

            map.put("brand", searchParam.get("brand"));
            map.put("area", searchParam.get("area"));
            map.put("specs", searchParam.get("specs"));
            map.put("sortWay", searchParam.get("sortWay"));
            map.put("minPrice", searchParam.get("minPrice"));
            map.put("maxPrice", searchParam.get("maxPrice"));
            //设置总页数
            map.put("totalPage", (totalHits + size - 1) / size);

            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }

    //品牌分组聚合
    @Override
    public Map<String, Object> searchBrandGroupQuery(Integer current, Integer size, Map<String, Object> searchParam) {

        /*//设置查询
        SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //设置查询方式
        if (!StringUtils.isEmpty(searchParam.get("condition"))) {
            QueryBuilder queryBuilder = QueryBuilders.queryStringQuery(searchParam.get("condition").toString())
                    .field("name")
                    .field("synopsis")
                    .field("area")
                    .field("address")
                    .defaultOperator(Operator.OR);
            searchSourceBuilder.query(queryBuilder);
        }

        //todo 按品牌分组聚合

        //设置分页
        searchSourceBuilder.from((current - 1) * size);
        searchSourceBuilder.size(size);

        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            List<HotelEntity> list = new ArrayList<>();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                list.add(JSON.parseObject(sourceAsString, HotelEntity.class));
            }

            //todo 获取并处理聚合查询结果


            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", totalHits);
            map.put("current", current);
            //设置总页数
            map.put("totalPage", (totalHits + size - 1) / size);

            //设置品牌分组列表
            //map.put("brandList", brandList);

            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }

    //自定义日期时间段聚合统计某品牌的酒店销量
    @Override
    public List<Map<String, Object>> searchDateHistogram(Map<String, Object> searchParam) {

        /*//定义结果集
        List<Map<String, Object>> result = new ArrayList<>();

        //设置查询
        SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //todo 自定义日期时间段范围查询

        //todo 聚合查询设置


        searchRequest.source(searchSourceBuilder);
        try {

            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            //todo 获取聚合结果并处理
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }
	
	//加权查询
    @Override
    public Map<String, Object> searchScoreQuery(Integer current, Integer size, Map<String, Object> searchParam) {

        /*SearchRequest searchRequest = new SearchRequest("hotel");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //todo 构建查询
        

        //设置分页
        searchSourceBuilder.from((current - 1) * size);
        searchSourceBuilder.size(size);

        searchRequest.source(searchSourceBuilder);

        try {
            //处理查询结果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits hits = searchResponse.getHits();

            long totalHits = hits.getTotalHits().value;

            SearchHit[] searchHits = hits.getHits();

            List<HotelEntity> list = new ArrayList<>();

            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                list.add(JSON.parseObject(sourceAsString, HotelEntity.class));
            }

            Map<String, Object> map = new HashMap<>();
            map.put("list", list);
            map.put("totalResultSize", totalHits);
            map.put("current", current);
            //设置总页数
            map.put("totalPage", (totalHits + size - 1) / size);

            return map;
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        return null;
    }

}
